package com.bsj.media.media.gb28181;

import com.bsj.power.common.def.protocol.rtp.RtpParameterSet;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;

/**
 * 解析H264 SPS系列参数集
 * 主要解析
 */
@Slf4j
public class decodeSPS {

    public static int Ue(byte[] pBuff, int nLen, int[] nStartBit) {
        // 计算0bit的个数
        int nZeroNum = 0;
        while (nStartBit[0] < nLen * 8) {
            if ((pBuff[nStartBit[0] / 8] & (0x80 >> (nStartBit[0] % 8))) != 0) // &:按位与，%取余
            {
                break;
            }
            nZeroNum++;
            nStartBit[0]++;
        }
        nStartBit[0]++;

        // 计算结果
        int dwRet = 0;
        for (int i = 0; i < nZeroNum; i++) {
            dwRet <<= 1;
            if ((pBuff[nStartBit[0] / 8] & (0x80 >> (nStartBit[0] % 8))) != 0) {
                dwRet += 1;
            }
            nStartBit[0]++;
        }
        return (1 << nZeroNum) - 1 + dwRet;
    }

    public static int Se(byte pBuff[], int nLen, int nStartBit[]) {
        int UeVal = Ue(pBuff, nLen, nStartBit);
        double k = UeVal;
        int nValue = (int) Math.ceil(k / 2);// ceil函数：ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
        if (UeVal % 2 == 0)
            nValue = -nValue;
        return nValue;
    }

    /**
     * @param BitCount:
     * @param buf:
     * @param nStartBit:
     * @Description: 无符号指数哥伦布熵编码
     * @return: int
     **/
    public static int u(int BitCount, byte[] buf, int[] nStartBit) {
        long dwRet = 0;
        for (int i = 0; i < BitCount; i++) {
            dwRet <<= 1;
            if ((buf[nStartBit[0] / 8] & (0x80 >> (nStartBit[0] % 8))) != 0) {
                dwRet += 1;
            }
            nStartBit[0]++;
        }
        return (int) (dwRet & 0xFFFFFFFFL);
    }

    /**
     * @param BitCount:
     * @param buf:
     * @param nStartBit:
     * @Description: 无符号指数哥伦布熵编码
     * @return: int
     **/
    private static long uL(int BitCount, byte[] buf, int[] nStartBit) {
        long dwRet = 0;
        for (int i = 0; i < BitCount; i++) {
            dwRet <<= 1;
            if ((buf[nStartBit[0] / 8] & (0x80 >> (nStartBit[0] % 8))) != 0) {
                dwRet += 1;
            }
            nStartBit[0]++;
        }
        return dwRet;
    }

    /**
     * H264的NAL起始码防竞争机制
     *
     * @param buf SPS数据内容
     * @无返回值
     */
    public static void de_emulation_prevention(byte buf[], int buf_size[]) {
        int i = 0, j = 0;
        byte[] tmp_ptr = buf;
        int tmp_buf_size = 0;
        int val = 0;

        // tmp_ptr=buf;
        tmp_buf_size = buf_size[0];
        for (i = 0; i < (tmp_buf_size - 2); i++) {
            // 查找 0x000003 其中0x03是假数据（为了解码时候误把视频里面的0x000001或者0x000001也当成NAL的起始码），解码需要把0x03给去掉
            val = (tmp_ptr[i] ^ 0x00) + (tmp_ptr[i + 1] ^ 0x00) + (tmp_ptr[i + 2] ^ 0x03);
            if (tmp_ptr[i] == 0 && tmp_ptr[i + 1] == 0 && tmp_ptr[i + 2] == 3) {
                // kick out 0x03
                for (j = i + 2; j < tmp_buf_size - 1; j++)
                    tmp_ptr[j] = tmp_ptr[j + 1];

                // and so we should devrease bufsize
                (buf_size[0])--;
            }
        }
    }

    /**
     * 查找h264 startcode
     *
     * @param buf
     * @param offset
     * @param size
     * @return
     */
    private static int FindStartCodeEx(byte[] buf, int offset, int size) {
        boolean bFound = false;
        int pos = offset;

        while (pos + 4 <= size) {
            if (buf[pos] != 0x0 || buf[pos + 1] != 0x0) {
                pos++;
                continue;
            }

            bFound = (buf[pos + 2] == 0x1) || (buf[pos + 2] == 0x0 && buf[pos + 3] == 0x1);

            if (bFound) {

                return pos;
            }
            pos += 1;

        }
        return -1;

    }

    /**
     * 查找P帧起始位置
     *
     * @param buffer      数据
     * @param nBufferSize 数据有用长度
     * @param offSet      起始偏移位
     * @param pt          1078的负载类型
     * @return 有则返回偏移位，没有返回-1
     */
    public static int ReadPFrameFromBuf(byte[] buffer, int nBufferSize, int offSet, int pt) {
        int start0 = 0;
        int start0_code_start_size = 0;

        if (offSet + 3 >= nBufferSize) {
            return -1;
        }
        // 查找h264 start code
        start0 = FindStartCodeEx(buffer, offSet, nBufferSize);
        if (start0 < 0) {
            return -1;
        }
        //判断h264 start code长度
        start0_code_start_size = (buffer[start0 + 2] == 0x1) ? 3 : 4;
        //if ((buffer[start0 + start0_code_start_size] & 0x1f) == 0x1){
        if (isRelevantNaluByPt(buffer, start0 + start0_code_start_size, pt, "p")) {
            //P帧, 返回h264 start code起始偏移位
            return start0;
        }
        return -1;
    }

    /**
     * 查找SPS帧，返回去掉头的数据
     *
     * @param buffer
     * @param nBufferSize
     * @param offSet
     * @param pt          1078中的负责类型，主要是h256和H264来判断查询SPS的值 98表示h264, 99表示h265
     * @return
     */
    public static byte[] ReadSPSNaluFromBuf(byte[] buffer, int nBufferSize, int offSet, int pt) {
        int start0 = 0, start1 = 0;
        int remain = 0;
        int start0_code_start_size = 0;

        if (offSet + 3 >= nBufferSize) {
            return null;
        }

        start0 = FindStartCodeEx(buffer, offSet, nBufferSize);

        if (start0 < 0) {
            return null;
        }
        //h264 开始头长度
        start0_code_start_size = (buffer[start0 + 2] == 0x1) ? 3 : 4;
        remain = nBufferSize - (start0 + start0_code_start_size);
        if (remain < 3) {
            return null;
        }
        //查找下一个h264帧数据头
        start1 = FindStartCodeEx(buffer, start0 + start0_code_start_size, nBufferSize);

        //if ((buffer[start0 + start0_code_start_size] & 0x1f) == 0x7) {
        while (start0 >= 0 && (start0 + start0_code_start_size < nBufferSize)) {
            //可能第一帧不是SPS数据，所有帧都需要检索对比下,防止数组越界
            if (isRelevantNaluByPt(buffer, start0 + start0_code_start_size, pt, "sps")) {
                if (start1 < 0) {
                    //说明当前帧里面只有SPS
                    return Arrays.copyOfRange(buffer, start0 + start0_code_start_size, nBufferSize);
                } else {
                    //说明还有其他帧
                    return Arrays.copyOfRange(buffer, start0 + start0_code_start_size, start1);
                }
            }
            start0 = start1;
            start1 = FindStartCodeEx(buffer, start0 + start0_code_start_size, nBufferSize);
        }


        return null;
    }

    /**
     * @param buffer:
     * @param offset:   buffer的Nalu类型偏移值
     * @param pt:       rtp中的负载类型, 如果不是h265,则按h264处理
     * @param naluType:
     * @Description: 根据pt类型的不同来判断是否有相应的NaluType
     * @return: boolean
     **/
    public static boolean isRelevantNaluByPt(byte[] buffer, int offset, int pt, String naluType) {

        // 相应pt,获取里面nalu的方式不同
        byte nalueNum = (byte) ((pt == RtpParameterSet.rtpCodeTypeH265) ? ((buffer[offset] & 0x7E) >> 1) : (buffer[offset] & 0x1f));

        switch (naluType) {
            case "sps":
                if (pt == RtpParameterSet.rtpCodeTypeH265) {
                    return nalueNum == RtpParameterSet.naluTypeSPSH5;
                } else {
                    return nalueNum == RtpParameterSet.naluTypeSPSH4;
                }
            case "p":
                if (pt == RtpParameterSet.rtpCodeTypeH265) {
                    return nalueNum == RtpParameterSet.naluTypeNotIDRH5;
                } else {
                    return nalueNum == RtpParameterSet.naluTypeNotIDRH4;
                }
            case "IDR":
                if (pt == RtpParameterSet.rtpCodeTypeH265) {
                    return nalueNum == RtpParameterSet.naluTypeIDRH5;
                } else  {
                    return nalueNum == RtpParameterSet.naluTypeIDRH4;
                }
            default:
                break;
        }
        return false;
    }

    /**
     * 判断当前SPS帧中，是否有关键帧
     *
     * @param buffer
     * @param nBufferSize
     * @param offSet
     * @param pt
     * @return
     */
    public static boolean JudgeHasKeyFrameNaluFromBuf(byte[] buffer, int nBufferSize, int offSet, int pt) {
        int start0 = 0;
        int start1 = 0;
        int remain = 0;
        int start0_code_start_size = 0;
        int loopTime = 0;
        while (loopTime < 5) {
            if (offSet + 3 >= nBufferSize) {
                return false;
            }

            start0 = FindStartCodeEx(buffer, offSet, nBufferSize);

            if (start0 < 0) {
                return false;
            }

            start0_code_start_size = (buffer[start0 + 2] == 0x1) ? 3 : 4;

            remain = nBufferSize - (start0 + start0_code_start_size);
            if (remain < 3) {
                return false;
            }

            start1 = FindStartCodeEx(buffer, start0 + start0_code_start_size, nBufferSize);

            int startcodeSize = (buffer[start0 + 2] == 0x1) ? 3 : 4;
            boolean isIDR = isRelevantNaluByPt(buffer, start0 + startcodeSize, pt, "IDR");
            if (start1 < 0) {
                //return (buffer[start0 + startcodeSize] & 0x1f) == 0x5;
                return isIDR;
            }

            // if ((buffer[start0 + startcodeSize] & 0x1f) == 0x5) {
            if (isIDR) {
                return true;
            }

            offSet = start1 - start0_code_start_size;
            //start0 = start1 - start0_code_start_size;
            loopTime++;
        }

        return false;
    }

    public static boolean h265_decode_sps(byte[] buf, int[] nLen, int[] width, int[] height, int[] fps) {
        int[] startBit = new int[1];
        de_emulation_prevention(buf, nLen);

        int forbidden_zero_bit = u(1, buf, startBit);
        int nal_unit_type = u(6, buf, startBit);
        int nuh_layer_id = u(6, buf, startBit);
        int nuh_temporal_plus1 = u(3, buf, startBit);
        if (nal_unit_type != 33) {
            return false;
        }
        int sps_video_parameter_set_id = u(4, buf, startBit);
        int sps_max_sub_layers_minusl = u(3, buf, startBit);
        int sps_temporal_id_nesting_flag = u(1, buf, startBit);

        // profile_tier_level
        int general_profile_space = u(2, buf, startBit);
        int general_tier_flag = u(1, buf, startBit);
        int general_profile_idc = u(5, buf, startBit);
        int[] general_profile_compatibility_flag = new int[32];
        for (int j = 0; j < 32; j++) {
            general_profile_compatibility_flag[j] = u(1, buf, startBit);
        }
        int general_progressive_source_flag = u(1, buf, startBit);
        int general_interlaced_source_flag = u(1, buf, startBit);
        int general_non_packed_constraint_flag = u(1, buf, startBit);
        int general_frame_only_constraint_flag = u(1, buf, startBit);
        if (general_profile_idc == 4 || general_profile_compatibility_flag[4] != 0 ||
                general_profile_idc == 5 || general_profile_compatibility_flag[5] != 0 ||
                general_profile_idc == 6 || general_profile_compatibility_flag[6] != 0 ||
                general_profile_idc == 7 || general_profile_compatibility_flag[7] != 0 ||
                general_profile_idc == 8 || general_profile_compatibility_flag[8] != 0 ||
                general_profile_idc == 9 || general_profile_compatibility_flag[9] != 0 ||
                general_profile_idc == 10 || general_profile_compatibility_flag[10] != 0 ||
                general_profile_idc == 11 || general_profile_compatibility_flag[11] != 0) {

            int general_max_12bit_constraint_flag = u(1, buf, startBit);
            int general_max_10bit_constraint_flag = u(1, buf, startBit);
            int general_max_8it_constraint_flag = u(1, buf, startBit);
            int general_max_422chroma_constraint_flag = u(1, buf, startBit);
            int general_max_420chroma_constraint_flag = u(1, buf, startBit);
            int general_max_monochrome_constraint_flag = u(1, buf, startBit);
            int general_intra_constraint_flag = u(1, buf, startBit);
            int general_one_picture_only_constraint_flag = u(1, buf, startBit);
            int general_lower_bit_rate_constraint_flag = u(1, buf, startBit);

            if (general_profile_idc == 5 || general_profile_compatibility_flag[5] != 0 ||
                    general_profile_idc == 9 || general_profile_compatibility_flag[9] != 0 ||
                    general_profile_idc == 10 || general_profile_compatibility_flag[10] != 0 ||
                    general_profile_idc == 11 || general_profile_compatibility_flag[11] != 0) {
                int general_max_14bit_constraint_flag = u(1, buf, startBit);
                long general_reserved_zero_33bits = uL(33, buf, startBit);
            } else {
                long general_reserved_zero_34bits = uL(34, buf, startBit);
            }
        } else if (general_profile_idc == 2 || general_profile_compatibility_flag[2] != 0) {
            int general_reserved_zero_7bits = u(7, buf, startBit);
            int general_one_picture_only_constraint_flag = u(1, buf, startBit);
            long general_reserved_zero_35bits = uL(35, buf, startBit);
        } else {
            long general_reserved_zero_43bits = uL(43, buf, startBit);
        }

        if (general_profile_idc == 1 || general_profile_compatibility_flag[4] != 0 ||
                general_profile_idc == 2 || general_profile_compatibility_flag[5] != 0 ||
                general_profile_idc == 3 || general_profile_compatibility_flag[6] != 0 ||
                general_profile_idc == 4 || general_profile_compatibility_flag[7] != 0 ||
                general_profile_idc == 5 || general_profile_compatibility_flag[8] != 0 ||
                general_profile_idc == 9 || general_profile_compatibility_flag[9] != 0 ||
                general_profile_idc == 11 || general_profile_compatibility_flag[11] != 0) {
            int general_inbld_flag = u(1, buf, startBit);
        } else {
            int general_reserved_zero_bit = u(1, buf, startBit);
        }

        int general_level_idc = u(8, buf, startBit);

        int[] sub_layer_profile_present_flag = new int[sps_max_sub_layers_minusl];
        int[] sub_layer_level_present_flag = new int[sps_max_sub_layers_minusl];
        for (int i = 0; i < sps_max_sub_layers_minusl; i++) {
            sub_layer_profile_present_flag[i] = u(1, buf, startBit);
            sub_layer_level_present_flag[i] = u(1, buf, startBit);
        }
        if (sps_max_sub_layers_minusl != 0) {
            for (int i = sps_max_sub_layers_minusl; i < 8; i++) {
                u(2, buf, startBit);
            }
        }
        int[] sub_layer_profile_space = new int[sps_max_sub_layers_minusl];
        int[] sub_layer_tier_flag = new int[sps_max_sub_layers_minusl];
        int[] sub_layer_profile_idc = new int[sps_max_sub_layers_minusl];
        int[][] sub_layer_profile_compatibility_flag = new int[sps_max_sub_layers_minusl][32];
        for (int i = 0; i < sps_max_sub_layers_minusl; i++) {
            if (sub_layer_profile_present_flag[i] != 0) {
                sub_layer_profile_space[i] = u(2, buf, startBit);
                sub_layer_tier_flag[i] = u(1, buf, startBit);
                sub_layer_profile_idc[i] = u(5, buf, startBit);
                for (int j = 0; j < 32; j++) {
                    sub_layer_profile_compatibility_flag[i][j] = u(1, buf, startBit);
                }
                u(1, buf, startBit); // sub_layer_progressive_source_fla
                u(1, buf, startBit); // sub_layer_interlaced_source_flag
                u(1, buf, startBit); // sub_layer_non_packed_constraint_flag
                u(1, buf, startBit); // sub_layer_frame_only_constraint_flag
                if (sub_layer_profile_idc[i] == 4 || sub_layer_profile_compatibility_flag[i][4] != 0 ||
                        sub_layer_profile_idc[i] == 5 || sub_layer_profile_compatibility_flag[i][5] != 0 ||
                        sub_layer_profile_idc[i] == 6 || sub_layer_profile_compatibility_flag[i][6] != 0 ||
                        sub_layer_profile_idc[i] == 7 || sub_layer_profile_compatibility_flag[i][7] != 0 ||
                        sub_layer_profile_idc[i] == 8 || sub_layer_profile_compatibility_flag[i][8] != 0 ||
                        sub_layer_profile_idc[i] == 9 || sub_layer_profile_compatibility_flag[i][9] != 0 ||
                        sub_layer_profile_idc[i] == 10 || sub_layer_profile_compatibility_flag[i][10] != 0 ||
                        sub_layer_profile_idc[i] == 11 || sub_layer_profile_compatibility_flag[i][11] != 0) {
                    u(1, buf, startBit); // sub_layer_max_12bit_constraint_flag
                    u(1, buf, startBit); //  sub_layer_max_10bit_constraint_flag
                    u(1, buf, startBit); // sub_layer_max_8bit_constraint_flag
                    u(1, buf, startBit); // sub_layer_max_422chroma_constraint_flag
                    u(1, buf, startBit); // sub_layer_max_420chroma_constraint_flag
                    u(1, buf, startBit); // sub_layer_max_monochrome_constraint_flag
                    u(1, buf, startBit); // sub_layer_intra_constraint_flag
                    u(1, buf, startBit); // sub_layer_one_picture_only_constraint_flag
                    u(1, buf, startBit); // sub_layer_lower_bit_rate_constraint_flag
                    if (sub_layer_profile_idc[i] == 5 || sub_layer_profile_compatibility_flag[i][5] != 0 ||
                            sub_layer_profile_idc[i] == 9 || sub_layer_profile_compatibility_flag[i][9] != 0 ||
                            sub_layer_profile_idc[i] == 10 || sub_layer_profile_compatibility_flag[i][10] != 0 ||
                            sub_layer_profile_idc[i] == 11 || sub_layer_profile_compatibility_flag[i][11] != 0) {
                        u(1, buf, startBit); // sub_layer_max_14bit_constraint_flag
                        uL(33, buf, startBit); // sub_layer_reserved_zero_33bits
                    } else {
                        uL(34, buf, startBit); // sub_layer_reserved_zero_34bits
                    }
                } else if (sub_layer_profile_idc[i] == 2 || sub_layer_profile_compatibility_flag[i][2] != 0) {
                    u(7, buf, startBit); // sub_layer_reserved_zero_7bits
                    u(1, buf, startBit); // sub_layer_one_picture_only_constraint_flag
                    uL(35, buf, startBit); // sub_layer_reserved_zero_35bits
                } else {
                    uL(43, buf, startBit);    // sub_layer_reserved_zero_43bits
                }
                if (sub_layer_profile_idc[i] == 1 || sub_layer_profile_compatibility_flag[i][1] != 0 ||
                        sub_layer_profile_idc[i] == 2 || sub_layer_profile_compatibility_flag[i][2] != 0 ||
                        sub_layer_profile_idc[i] == 3 || sub_layer_profile_compatibility_flag[i][3] != 0 ||
                        sub_layer_profile_idc[i] == 4 || sub_layer_profile_compatibility_flag[i][4] != 0 ||
                        sub_layer_profile_idc[i] == 5 || sub_layer_profile_compatibility_flag[i][5] != 0 ||
                        sub_layer_profile_idc[i] == 9 || sub_layer_profile_compatibility_flag[i][9] != 0 ||
                        sub_layer_profile_idc[i] == 11 || sub_layer_profile_compatibility_flag[i][11] != 0) {
                    u(1, buf, startBit); // sub_layer_inbld_flag
                } else {
                    u(1, buf, startBit); // sub_layer_reserved_zero_bit
                }
            }
            if (sub_layer_level_present_flag[i] != 0) {
                u(8, buf, startBit); // sub_layer_level_idc
            }
        }

        int sps_seq_parameter_set_id = Ue(buf, nLen[0], startBit);
        int chroma_format_idc = Ue(buf, nLen[0], startBit);
        int separate_colour_plane_flag = 0;
        if (chroma_format_idc == 3) {
            separate_colour_plane_flag = u(1, buf, startBit);
        }
        width[0] = Ue(buf, nLen[0], startBit);
        height[0] = Ue(buf, nLen[0], startBit);
        int conformance_window_flag = u(1, buf, startBit);
        if (conformance_window_flag != 0) {
            int conf_win_left_offset = Ue(buf, nLen[0], startBit);
            int conf_win_right_offset = Ue(buf, nLen[0], startBit);
            int conf_win_top_offset = Ue(buf, nLen[0], startBit);
            int conf_win_bottom_offset = Ue(buf, nLen[0], startBit);
            if (conformance_window_flag == 1) {
                // 重新计算宽高
                int sub_width_c = ((1 == chroma_format_idc) || (2 == chroma_format_idc)) && (0 == separate_colour_plane_flag) ? 2 : 1;
                int sub_heigth_c = (1 == chroma_format_idc) && (0 == separate_colour_plane_flag) ? 2 : 1;
                width[0] -= (sub_width_c * conf_win_right_offset + sub_width_c * conf_win_left_offset);
                height[0] -= (sub_heigth_c * conf_win_bottom_offset + sub_heigth_c * conf_win_top_offset);
            }
        }
        Ue(buf, nLen[0], startBit); // bit_depth_luma_minus8
        Ue(buf, nLen[0], startBit); // bit_depth_chroma_minus8
        int log2_max_pic_order_cnt_lsb_minus4 = Ue(buf, nLen[0], startBit);
        int sps_sub_layer_ordering_info_present_flag = u(1, buf, startBit);
        for (int i = (sps_sub_layer_ordering_info_present_flag != 0 ? 0 : sps_max_sub_layers_minusl); i <= sps_max_sub_layers_minusl; i++) {
            Ue(buf, nLen[0], startBit); // sps_max_dec_pic_buffering_minus1[ i ]
            Ue(buf, nLen[0], startBit); // sps_max_num_reorder_pics[ i ]
            Ue(buf, nLen[0], startBit); // sps_max_latency_increase_plus1[ i ]
        }
        Ue(buf, nLen[0], startBit); // log2_min_luma_coding_block_size_minus3
        Ue(buf, nLen[0], startBit); // log2_diff_max_min_luma_coding_block_size
        Ue(buf, nLen[0], startBit); // log2_min_luma_transform_block_size_minus2
        Ue(buf, nLen[0], startBit); // log2_diff_max_min_luma_transform_block_size
        Ue(buf, nLen[0], startBit); // max_transform_hierarchy_depth_inter
        Ue(buf, nLen[0], startBit); // max_transform_hierarchy_depth_intra
        int scaling_list_enabled_flag = u(1, buf, startBit);
        if (scaling_list_enabled_flag != 0) {
            int sps_scaling_list_data_present_flag = u(1, buf, startBit);
            if (sps_scaling_list_data_present_flag != 0) {
                //scaling_list_data()
                int[][] scaling_list_pred_mode_flag = new int[4][6];
                int[][] scaling_list_dc_coef_minus8 = new int[4][6];
                for (int sizeId = 0; sizeId < 4; sizeId++) {
                    for (int matrixId = 0; matrixId < 6; matrixId += (sizeId == 3) ? 3 : 1) {
                        scaling_list_pred_mode_flag[sizeId][matrixId] = u(1, buf, startBit);
                        if (scaling_list_pred_mode_flag[sizeId][matrixId] == 0) {
                            Ue(buf, nLen[0], startBit); // scaling_list_pred_matrix_id_delta[ sizeId ][ matrixId ]
                        } else {
                            int nextCoef = 8;
                            int coefNum = Math.min(64, (1 << (4 + (sizeId << 1))));
                            if (sizeId > 1) {
                                scaling_list_dc_coef_minus8[sizeId - 2][matrixId] = Se(buf, nLen[0], startBit);
                                nextCoef = scaling_list_dc_coef_minus8[sizeId - 2][matrixId] + 8;
                            }
                            for (int i = 0; i < coefNum; i++) {
                                int scaling_list_delta_coef = Se(buf, nLen[0], startBit);
                                nextCoef = (nextCoef + scaling_list_delta_coef + 256) % 256;
                            }
                        }
                    }
                }
            }
        }

        int amp_enabled_flag = u(1, buf, startBit);
        int sample_adaptive_offset_enabled_flag = u(1, buf, startBit);
        int pcm_enabled_flag = u(1, buf, startBit);
        if (pcm_enabled_flag != 0) {
            u(4, buf, startBit);
            u(4, buf, startBit);
            Ue(buf, nLen[0], startBit);
            Ue(buf, nLen[0], startBit);
            u(1, buf, startBit);
        }
        int num_short_term_ref_pic_sets = Ue(buf, nLen[0], startBit);
        for (int i = 0; i < num_short_term_ref_pic_sets; i++) {
            int inter_ref_pic_set_prediction_flag = 0;
            if (i != 0) {
                inter_ref_pic_set_prediction_flag = u(1, buf, startBit); // inter_ref_pic_set_prediction_flag
            }
            if (inter_ref_pic_set_prediction_flag != 0) {
                int delta_idx_minus1 = 0;
                if (i == num_short_term_ref_pic_sets)
                    delta_idx_minus1 = Ue(buf, nLen[0], startBit); // 	delta_idx_minus1
                u(1, buf, startBit); // delta_rps_sign
                Ue(buf, nLen[0], startBit); // abs_delta_rps_minus1
                int retRpsIdx = i - (delta_idx_minus1 + 1);
                for (int j=0; j<=retRpsIdx; j++) {
                    int used_by_curr_pic_flag = u(1, buf, startBit); // used_by_curr_pic_flag
                    if (used_by_curr_pic_flag == 0) {
                        u(1, buf, startBit); // use_delta_flag
                    }
                }
            } else {
                int num_negative_pics = Ue(buf, nLen[0], startBit); // num_negative_pics
                int num_positive_pics = Ue(buf, nLen[0], startBit); // num_positive_pics
                for (int i3 = 0; i3 < num_negative_pics; i3++) {
                    Ue(buf, nLen[0], startBit); // delta_poc_s0_minus1
                    u(1, buf, startBit); //used_by_curr_pic_s0_flag
                }
                for (int i4 = 0; i4 < num_positive_pics; i4++) {
                    Ue(buf, nLen[0], startBit); // delta_poc_s1_minus1
                    u(1, buf, startBit); //used_by_curr_pic_s1_flag
                }
            }
        }
        int long_term_ref_pics_present_flag = u(1, buf, startBit);
        if (long_term_ref_pics_present_flag != 0) {
            int num_long_term_ref_pics_sps = Ue(buf, nLen[0], startBit);
            for (int i = 0; i < num_long_term_ref_pics_sps; i++) {
                Ue(buf, nLen[0], startBit); // lt_ref_pic_poc_lsb_sps[ i ]
                u(1, buf, startBit); // used_by_curr_pic_lt_sps_flag[ i ]
            }
        }
        u(1, buf, startBit); // sps_temporal_mvp_enabled_flag
        u(1, buf, startBit); // strong_intra_smoothing_enabled_flag
        int vui_parameters_present_flag = u(1, buf, startBit);
        if (vui_parameters_present_flag != 0) {
            // 计算帧率
            int aspect_ratio_info_present_flag = u(1, buf, startBit);
            if (aspect_ratio_info_present_flag != 0) {
                int aspect_ratio_idc = u(8, buf, startBit);
                if (aspect_ratio_idc == 255) {
                    u(16, buf, startBit); //  sar_width
                    u(16, buf, startBit); // sar_height
                }
            }
            int overscan_info_present_flag = u(1, buf, startBit);
            if (overscan_info_present_flag != 0) {
                u(1, buf, startBit); // overscan_appropriate_flag
            }
            int video_signal_type_present_flag = u(1, buf, startBit);
            if (video_signal_type_present_flag != 0) {
                u(3, buf, startBit); // video_format
                u(1, buf, startBit); // video_full_range_flag
                int colour_description_present_flag = u(1, buf, startBit);
                if (colour_description_present_flag != 0) {
                    u(8, buf, startBit);
                    u(8, buf, startBit);
                    u(8, buf, startBit);
                }
            }

            int chroma_loc_info_present_flag = u(1, buf, startBit);
            if (chroma_loc_info_present_flag != 0) {
                Ue(buf, nLen[0], startBit);
                Ue(buf, nLen[0], startBit);
            }
            u(1, buf, startBit);
            u(1, buf, startBit);
            u(1, buf, startBit);
            int default_display_window_flag = u(1, buf, startBit);
            if (default_display_window_flag != 0) {
                Ue(buf, nLen[0], startBit);
                Ue(buf, nLen[0], startBit);
                Ue(buf, nLen[0], startBit);
                Ue(buf, nLen[0], startBit);
            }
            // 帧率标识
            int vui_timing_info_present_flag = u(1, buf, startBit);
            if (vui_timing_info_present_flag != 0) {
                long vui_num_units_in_tick = uL(32, buf, startBit);
                long vui_time_scale = uL(32, buf, startBit);
                fps[0] = (int) (vui_time_scale / vui_num_units_in_tick);
            }
        }
        return true;
    }

    /**
     * 解码SPS,获取视频图像宽、高和帧率信息
     *
     * @param buf    SPS数据内容
     * @param nLen   SPS数据的长度
     * @param width  图像宽度
     * @param height 图像高度
     * @param fps    帧率
     * @成功则返回true , 失败则返回false
     */
    @SuppressWarnings("unused")
    public static boolean h264_decode_sps(byte[] buf, int[] nLen, int[] width, int[] height, int[] fps) {
        int[] StartBit = new int[1];
        de_emulation_prevention(buf, nLen);

        int forbidden_zero_bit = u(1, buf, StartBit);
        int nal_ref_idc = u(2, buf, StartBit);
        int nal_unit_type = u(5, buf, StartBit); // NALU单元的类型，7表示SPS帧
        if (nal_unit_type == 7) {
            int profile_idc = u(8, buf, StartBit);
            int constraint_set0_flag = u(1, buf, StartBit);// (buf[1] & 0x80)>>7;
            int constraint_set1_flag = u(1, buf, StartBit);// (buf[1] & 0x40)>>6;
            int constraint_set2_flag = u(1, buf, StartBit);// (buf[1] & 0x20)>>5;
            int constraint_set3_flag = u(1, buf, StartBit);// (buf[1] & 0x10)>>4;
            int reserved_zero_4bits = u(4, buf, StartBit);
            int level_idc = u(8, buf, StartBit);

            int seq_parameter_set_id = Ue(buf, nLen[0], StartBit);

            if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) {
                int chroma_format_idc = Ue(buf, nLen[0], StartBit);
                if (chroma_format_idc == 3) {
                    int residual_colour_transform_flag = u(1, buf, StartBit);
                }
                int bit_depth_luma_minus8 = Ue(buf, nLen[0], StartBit);
                int bit_depth_chroma_minus8 = Ue(buf, nLen[0], StartBit);
                int qpprime_y_zero_transform_bypass_flag = u(1, buf, StartBit);
                int seq_scaling_matrix_present_flag = u(1, buf, StartBit);

                int[] seq_scaling_list_present_flag = new int[8];
                if (seq_scaling_matrix_present_flag != 0) {
                    for (int i = 0; i < 8; i++) {
                        seq_scaling_list_present_flag[i] = u(1, buf, StartBit);
                        // 新加begin
                        if (seq_scaling_list_present_flag[i] != 0) {
                            /* seq_scaling_list_present */
                            int last = 8, next = 8, size = (i < 6) ? 16 : 64;
                            for (int j = 0; j < size; j++) {

                                if (next != 0) {
                                    next = (last + Se(buf, nLen[0], StartBit)) & 0xff;
                                }
                                last = next > 0 ? next : last;
                            }
                        }
                        // 新加end
                    }
                }
            }
            int log2_max_frame_num_minus4 = Ue(buf, nLen[0], StartBit);
            int pic_order_cnt_type = Ue(buf, nLen[0], StartBit);
            if (pic_order_cnt_type == 0) {
                int log2_max_pic_order_cnt_lsb_minus4 = Ue(buf, nLen[0], StartBit);
            } else if (pic_order_cnt_type == 1) {
                int delta_pic_order_always_zero_flag = u(1, buf, StartBit);
                int offset_for_non_ref_pic = Se(buf, nLen[0], StartBit);
                int offset_for_top_to_bottom_field = Se(buf, nLen[0], StartBit);
                int num_ref_frames_in_pic_order_cnt_cycle = Ue(buf, nLen[0], StartBit);

                int[] offset_for_ref_frame = new int[num_ref_frames_in_pic_order_cnt_cycle];
                for (int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
                    offset_for_ref_frame[i] = Se(buf, nLen[0], StartBit);
                }
            }
            int num_ref_frames = Ue(buf, nLen[0], StartBit);
            int gaps_in_frame_num_value_allowed_flag = u(1, buf, StartBit);
            int pic_width_in_mbs_minus1 = Ue(buf, nLen[0], StartBit);
            int pic_height_in_map_units_minus1 = Ue(buf, nLen[0], StartBit);

            width[0] = (pic_width_in_mbs_minus1 + 1) * 16;
            height[0] = (pic_height_in_map_units_minus1 + 1) * 16;

            int frame_mbs_only_flag = u(1, buf, StartBit);
            if (frame_mbs_only_flag == 0) {
                int mb_adaptive_frame_field_flag = u(1, buf, StartBit);
            }

            int direct_8x8_inference_flag = u(1, buf, StartBit);
            int frame_cropping_flag = u(1, buf, StartBit);
            if (frame_cropping_flag != 0) {
                int frame_crop_left_offset = Ue(buf, nLen[0], StartBit);
                int frame_crop_right_offset = Ue(buf, nLen[0], StartBit);
                int frame_crop_top_offset = Ue(buf, nLen[0], StartBit);
                int frame_crop_bottom_offset = Ue(buf, nLen[0], StartBit);

                width[0] -= 2 * (frame_crop_left_offset + frame_crop_right_offset);
                if (frame_mbs_only_flag != 0) {
                    height[0] -= 2 * (frame_crop_top_offset + frame_crop_bottom_offset);
                } else {
                    height[0] -= 4 * (frame_crop_top_offset + frame_crop_bottom_offset);
                }
            }
            int vui_parameter_present_flag = u(1, buf, StartBit);
            if (vui_parameter_present_flag != 0) {
                int aspect_ratio_info_present_flag = u(1, buf, StartBit);
                if (aspect_ratio_info_present_flag != 0) {
                    int aspect_ratio_idc = u(8, buf, StartBit);
                    if (aspect_ratio_idc == 255) {
                        int sar_width = u(16, buf, StartBit);
                        int sar_height = u(16, buf, StartBit);
                    }
                }
                int overscan_info_present_flag = u(1, buf, StartBit);
                if (overscan_info_present_flag != 0) {
                    int overscan_appropriate_flagu = u(1, buf, StartBit);
                }
                int video_signal_type_present_flag = u(1, buf, StartBit);
                if (video_signal_type_present_flag != 0) {
                    int video_format = u(3, buf, StartBit);
                    int video_full_range_flag = u(1, buf, StartBit);
                    int colour_description_present_flag = u(1, buf, StartBit);
                    if (colour_description_present_flag != 0) {
                        int colour_primaries = u(8, buf, StartBit);
                        int transfer_characteristics = u(8, buf, StartBit);
                        int matrix_coefficients = u(8, buf, StartBit);
                    }
                }
                int chroma_loc_info_present_flag = u(1, buf, StartBit);
                if (chroma_loc_info_present_flag != 0) {
                    int chroma_sample_loc_type_top_field = Ue(buf, nLen[0], StartBit);
                    int chroma_sample_loc_type_bottom_field = Ue(buf, nLen[0], StartBit);
                }
                int timing_info_present_flag = u(1, buf, StartBit);

                if (timing_info_present_flag != 0) {
                    int num_units_in_tick = u(32, buf, StartBit);
                    int time_scale = u(32, buf, StartBit);
                    fps[0] = time_scale / num_units_in_tick;
                    int fixed_frame_rate_flag = u(1, buf, StartBit);
                    if (fixed_frame_rate_flag != 0) {
                        fps[0] = fps[0] / 2;
                    }
                }
            }
            return true;
        } else {
            return false;
        }
    }

}
